"""
NAME:
  string2radec
PURPOSE:
  Code for string transformation of coordinates
FUNCTIONS:
  string2radec()
  radec2string()
"""

__author__ = 'Michael Blanton <michael.blanton@gmail.com>'

__version__ = '$Revision: 8 $'.split(': ')[1].split()[0]

__all__ = [ 'string2radec', 'radec2string', 'string2ra', 'string2dec']

#
# Modules
#
import re
from math import *
from numpy import *

#
# Classes
#
		
#
# Functions
#

def string2ra(string):
	div='(|:|\s)'
	sra='(\d\d)'+div+'(\d\d)'+div+'(\d\d)(\.?\d*|)'
	
	co_re= re.compile(sra)
	co_search= co_re.search(string)
	
	if(co_search is None):
		return 
	elems=co_search.groups()
	
	# Check for nonsense values
	if(double(elems[0])>24.):
		return
	if(double(elems[2])>=60.):
		return
	if(double(elems[4])>=60.):
		return
		
	# Convert ra
	ra= (double(elems[0])*double(15.)+
		 double(elems[2])*double(15./60.)+
		 double(elems[4])*double(15./3600.))
	if(elems[5] != '' and elems[5] != '.'):
		ra=ra+double(elems[5])*double(15./3600.)
	if(ra>360.):
		return
	
	return ra

def string2dec(string):
	div='(|:|\s)'
	sdec='(\s*|\s*\+|\s*\-)'+'(\d\d)'+div+'(\d\d)'+div+'(\d\d)(\.?\d*|)'
	
	co_re= re.compile(sdec)
	co_search= co_re.search(string)
	
	if(co_search is None):
		return 
	elems=co_search.groups()
	
	# Check for nonsense values
	if(double(elems[1])>90.):
		return
	if(double(elems[3])>=60.):
		return
	if(double(elems[5])>=60.):
		return
		
	# Convert dec
	dec= (double(elems[1])+
		  double(elems[3])/double(60.)+
		  double(elems[5])/double(3600.))
	if(elems[6] != '' and elems[6] != '.'):
		dec=dec+double(elems[6])/double(3600.)
	if(dec>90.):
		return
	if(re.match('\s*\-', elems[0])):
		dec=double(-1.)*dec
	
	return dec

def string2radec(string):
	"""
	NAME:
	  string2radec
	PURPOSE
	  Converting from a string to ra and dec
	CALLING SEQUENCE:
	  (ra, dec)= string2radec(string)
	COMMENTS:
	  Converts any string of the following forms to decimal:
	   HH MM SS[.S] [+|-]DD MM SS[.S]
	   HH:MM:SS[.S] [+|-]DD:MM:SS[.S]
	   HHMMSS[.S][+|-]DDMMSS[.S]
	  It returns an (ra, dec) tuple.  For non-valid strings, or
	  coordinates out of range, it retuns None.
	AUTHOR:
	  Mike Blanton, NYU 2009-10-31
	"""

	# Parse the string into elements
	div='(|:|\s)'
	sra='(\d\d)'+div+'(\d\d)'+div+'(\d\d)(\.?\d*|)'
	sdec='(\s*|\s*\+|\s*\-)'+'(\d\d)'+div+'(\d\d)'+div+'(\d\d)(\.?\d*|)'
	sradec= sra+sdec
	co_re= re.compile(sradec)
	co_search= co_re.search(string)
	if(co_search is None):
		return 
	elems=co_search.groups()
	
	# Check for nonsense values
	if(double(elems[0])>24.):
		return
	if(double(elems[2])>=60.):
		return
	if(double(elems[4])>=60.):
		return
	if(double(elems[7])>90.):
		return
	if(double(elems[9])>=60.):
		return
	if(double(elems[11])>=60.):
		return

	# Convert ra
	ra= (double(elems[0])*double(15.)+
		 double(elems[2])*double(15./60.)+
		 double(elems[4])*double(15./3600.))
	if(elems[5] != '' and elems[5] != '.'):
		ra=ra+double(elems[5])*double(15./3600.)
	if(ra>360.):
		return 

	# Convert dec
	dec= (double(elems[7])+
		  double(elems[9])/double(60.)+
		  double(elems[11])/double(3600.))
	if(elems[12] != '' and elems[12] != '.'):
		dec=dec+double(elems[12])/double(3600.)
	if(dec>90.):
		return
	if(re.match('\s*\-', elems[6])):
		dec=double(-1.)*dec
		
	return (ra, dec)

def radec2string(ra, dec, sep=':', nsig=2):
	"""
	NAME:
	  radec2string
	PURPOSE
	  Converting from ra and dec to a string
	CALLING SEQUENCE:
	  string= radec2string(ra, dec [, sep=, nsig=] )
	INPUTS:
	  ra, dec - decimal ra, dec in deg
	OPTIONAL INPUTS:
	  sep - separator string (default ':')
	  nsig - number of digits past decimal in RA (default 2)
	COMMENTS:
	  Converts decimal ra and dec to form:
		 HH:MM:SS.SS[+/-]DD:MM:SS.S
	  Optional argument 'sep' specifies separator (default ':')
	  Optional argument 'nsig' specifies number of decimal digits in RA
		(default 2); one less used for Dec
	  Coordinates are TRUNCATED not ROUNDED
	AUTHOR:
	  Mike Blanton, NYU 2009-10-31
	"""

	if(nsig<=0):
		nsigra=0
		nsigdec=0
	else:
		nsigra=nsig
		nsigdec=nsig-1

	rahr= long(ra/15.)
	ramin= long((ra/15.- double(rahr))*60.)
	rasec= ((ra/15.- double(rahr))*60.- double(ramin))*60.
	rasec= double(long(rasec*pow(10., nsigra))/pow(10., nsigra))

	if(dec<0.):
		decsign='-'
	else:
		decsign='+'
	adec=abs(dec)
	decdeg= long(adec)
	decmin= long((double(adec)- double(decdeg))*60.)
	decsec= ((double(adec)- double(decdeg)- double(decmin)/60.)*3600.)
	decsec= double(long(decsec*pow(10., nsigdec))/pow(10., nsigdec))

	if(nsigra==0):
		fra="%02d"
	else:
		fra="%0"+str(nsigra+3)+"."+str(nsigra)+"f"
	if(nsigdec==0):
		fdec="%02d"
	else:
		fdec="%0"+str(nsigdec+3)+"."+str(nsigdec)+"f"

	rastr= "%02d"+sep+"%02d"+sep+fra
	rastr= rastr % (rahr, ramin, rasec)
	decstr= decsign+"%02d"+sep+"%02d"+sep+fdec
	decstr= decstr % (decdeg, decmin, decsec)

	return rastr+decstr
	
#
# Unit tests
#
if __name__ == '__main__':
	print "Testing string2radec->radec2string"
	sts= ['05:33:22.54+89:00:01.4',
		  '05:33:22.54 89:00:01.4',
		  '05:33:22.5489:00:01.4',
		  '053322.54 890001.4',
		  '23:22:00.34-00:30:33.2',
		  '232200.34-003033.2',
		  '12:55:10.34-30:10:37.2']
	for st in sts:
		  (ra, dec)= string2radec(st)
		  stback= radec2string(ra, dec)
		  print st, "->", ra, dec, "->", stback
	

